home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / utility1 / gsview08.zip / PRINT.C < prev    next >
C/C++ Source or Header  |  1993-07-06  |  23KB  |  809 lines

  1. /*
  2.  * print.c --   Printing operations for GSVIEW.EXE, 
  3.  *              a graphical interface for MS-Windows Ghostscript
  4.  * Copyright (C) 1993  Russell Lang
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   Author: Russell Lang
  21.  * Internet: rjl@monu1.cc.monash.edu.au
  22.  */
  23.  
  24. #define STRICT
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <commdlg.h>
  28. #include <shellapi.h>
  29. #include <mmsystem.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <dir.h>
  35. #include <io.h>
  36. #define NeedFunctionPrototypes 1
  37. #include "ps.h"
  38. #include "gsview.h"
  39.  
  40. static char pcfname[MAXSTR];    /* name of temporary command file for printing */
  41. static char pfname[MAXSTR];    /* name of temporary file for printing options */
  42.  
  43. /* documented in Device Driver Adaptation Guide */
  44. /* Prototypes taken from print.h */
  45. DECLARE_HANDLE(HPJOB);
  46.  
  47. HPJOB   WINAPI OpenJob(LPSTR, LPSTR, HPJOB);
  48. int     WINAPI StartSpoolPage(HPJOB);
  49. int     WINAPI EndSpoolPage(HPJOB);
  50. int     WINAPI WriteSpool(HPJOB, LPSTR, int);
  51. int     WINAPI CloseJob(HPJOB);
  52. int     WINAPI DeleteJob(HPJOB, int);
  53. int     WINAPI WriteDialog(HPJOB, LPSTR, int);
  54. int     WINAPI DeleteSpoolPage(HPJOB);
  55.  
  56. struct prop_item_s {
  57.     char    name[MAXSTR];
  58.     char    value[MAXSTR];
  59. };
  60.  
  61. char not_defined[] = "[Not defined]";
  62.  
  63. struct prop_item_s *
  64. get_properties(char *device)
  65. {
  66. char *entries, *p;
  67. int i, numentry;
  68. struct prop_item_s *proplist;
  69.     entries = malloc(PROFILE_SIZE);
  70.     if (entries == (char *)NULL)
  71.        return NULL;
  72.     GetPrivateProfileString(device, NULL, "", entries, PROFILE_SIZE, INIFILE);
  73.     if (strlen(entries) == 0) {
  74.         free(entries);
  75.         return NULL;
  76.     }
  77.     p = entries;
  78.     for (numentry=0; p!=(char *)NULL && strlen(p)!=0; numentry++)
  79.         p += strlen(p) + 1;
  80.     proplist = (struct prop_item_s *)malloc((numentry+1) * sizeof(struct prop_item_s));
  81.     if (proplist == (struct prop_item_s *)NULL) {
  82.         free(entries);
  83.         return NULL;
  84.     }
  85.     p = entries;
  86.     for (i=0; i<numentry; i++) {
  87.         strcpy(proplist[i].name, p);
  88.         GetPrivateProfileString(device, p, "", proplist[i].value, sizeof(proplist->value), INIFILE);
  89.         p += strlen(p) + 1;
  90.     }
  91.     proplist[numentry].name[0] = '\0';
  92.     proplist[numentry].value[0] = '\0';
  93.     free(entries);
  94.     return proplist;
  95. }
  96.  
  97. /* dialog box for selecting printer properties */
  98. BOOL CALLBACK _export
  99. PropDlgProc(HWND hDlg, UINT wmsg, WPARAM wParam, LPARAM lParam)
  100. {
  101.     char buf[128];
  102.     int iprop;
  103.     int ivalue;
  104.     WORD notify_message;
  105.     char *p;
  106.     char *value;
  107.     static char device[MAXSTR];    /* contains printer device name */
  108.     static struct prop_item_s* propitem;
  109.     char section[MAXSTR];
  110.  
  111.     switch (wmsg) {
  112.         case WM_INITDIALOG:
  113.         lstrcpy(device, (LPSTR)lParam);    /* initialise device name */
  114.         propitem = get_properties(device);
  115.         if (propitem == (struct prop_item_s *)NULL) {
  116.             EndDialog(hDlg, FALSE);
  117.             return TRUE;
  118.         }
  119.         for (iprop=0; propitem[iprop].name[0]; iprop++) {
  120.             SendDlgItemMessage(hDlg, PROP_NAME, CB_ADDSTRING, 0, 
  121.             (LPARAM)((LPSTR)propitem[iprop].name+1));
  122.         }
  123.         SendDlgItemMessage(hDlg, PROP_NAME, CB_SETCURSEL, 0, 0L);
  124.         /* force update of PROP_VALUE */
  125.         SendDlgNotification(hDlg, PROP_NAME, CBN_SELCHANGE);
  126.         return TRUE;
  127.         case WM_COMMAND:
  128.         notify_message = GetNotification(wParam,lParam);
  129.         switch (LOWORD(wParam)) {
  130.             case ID_HELP:
  131.                 SendMessage(hwndimg, help_message, 0, 0L);
  132.                 return(FALSE);
  133.             case PROP_NAME:
  134.             if (notify_message != CBN_SELCHANGE) {
  135.                 return FALSE;
  136.             }
  137.             iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  138.             if (iprop == CB_ERR) {
  139.                 return FALSE;
  140.             }
  141.             /* now look up entry in gsview.ini */
  142.             /* and update PROP_VALUE list box */
  143.             strcpy(section, device);
  144.             strcat(section, " values");
  145.             GetPrivateProfileString(section, propitem[iprop].name, "", buf, sizeof(buf)-2, INIFILE);
  146.             buf[strlen(buf)+1] = '\0';    /* put double NULL at end */
  147.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_RESETCONTENT, 0, 0L);
  148.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_ADDSTRING, 0, 
  149.                 (LPARAM)((LPSTR)not_defined));
  150.             p = buf;
  151.             if (*p != '\0') {
  152.               EnableWindow(GetDlgItem(hDlg, PROP_VALUE), TRUE);
  153.               while (*p!='\0') {
  154.                 value = p;
  155.                 while ((*p!='\0') && (*p!=','))
  156.                 p++;
  157.                 *p++ = '\0';
  158.                     SendDlgItemMessage(hDlg, PROP_VALUE, CB_ADDSTRING, 0, 
  159.                     (LPARAM)((LPSTR)value));
  160.               }
  161.             }
  162.             SendDlgItemMessage(hDlg, PROP_VALUE, CB_SELECTSTRING, -1, (LPARAM)(LPSTR)propitem[iprop].value);
  163.                 SetDlgItemText(hDlg, PROP_VALUE, propitem[iprop].value);
  164.             return FALSE;
  165.             case PROP_VALUE:
  166.             if (notify_message == CBN_SELCHANGE) {
  167.                 iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  168.                 if (iprop == CB_ERR)
  169.                     return FALSE;
  170.                 ivalue = (int)SendDlgItemMessage(hDlg, PROP_VALUE, CB_GETCURSEL, 0, 0L);
  171.                 if (ivalue == CB_ERR)
  172.                     return FALSE;
  173.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_GETLBTEXT, ivalue, (LPARAM)(LPSTR)propitem[iprop].value);
  174.             }
  175.             if (notify_message == CBN_EDITCHANGE) {
  176.                 iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  177.                 if (iprop == CB_ERR)
  178.                     return FALSE;
  179.                     GetDlgItemText(hDlg, PROP_VALUE, (LPSTR)propitem[iprop].value, sizeof(propitem->value));
  180.             }
  181.             return FALSE;
  182.             case IDOK:
  183.             for (iprop=0; propitem[iprop].name[0]; iprop++) {
  184.                 WritePrivateProfileString(device, propitem[iprop].name, propitem[iprop].value, INIFILE);
  185.             }
  186.             free((char *)propitem);
  187.             EndDialog(hDlg, TRUE);
  188.             return TRUE;
  189.             case IDCANCEL:
  190.             free((char *)propitem);
  191.             EndDialog(hDlg, FALSE);
  192.             return TRUE;
  193.         }
  194.         break;
  195.     }
  196.     return FALSE;
  197. }
  198.  
  199.  
  200. /* dialog box for selecting printer device and resolution */
  201. BOOL CALLBACK _export
  202. DeviceDlgProc(HWND hDlg, UINT wmsg, WPARAM wParam, LPARAM lParam)
  203. {
  204.     char buf[128];
  205.     int idevice;
  206.     WORD notify_message;
  207.     char *p;
  208.     char *res;
  209.     int numentry;
  210.     char entry[MAXSTR];
  211.     struct prop_item_s *proplist;
  212.  
  213.     switch (wmsg) {
  214.         case WM_INITDIALOG:
  215.         p = get_devices();
  216.         res = p;    /* save for free() */
  217.         for (numentry=0; p!=(char *)NULL && strlen(p)!=0; numentry++) {
  218.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_ADDSTRING, 0, 
  219.             (LPARAM)((LPSTR)p));
  220.             p += strlen(p) + 1;
  221.         }
  222.         free(res);
  223.         if (SendDlgItemMessage(hDlg, DEVICE_NAME, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)device_name)
  224.             == CB_ERR)
  225.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_SETCURSEL, 0, 0L);
  226.         /* force update of DEVICE_RES */
  227.         SendDlgNotification(hDlg, DEVICE_NAME, CBN_SELCHANGE);
  228.         if (SendDlgItemMessage(hDlg, DEVICE_RES, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)device_resolution)
  229.             == CB_ERR)
  230.             SendDlgItemMessage(hDlg, DEVICE_RES, CB_SETCURSEL, 0, 0L);
  231.         return TRUE;
  232.         case WM_COMMAND:
  233.         notify_message = GetNotification(wParam,lParam);
  234.         switch (LOWORD(wParam)) {
  235.             case ID_HELP:
  236.                 SendMessage(hwndimg, help_message, 0, 0L);
  237.                 return(FALSE);
  238.             case DEVICE_NAME:
  239.             if (notify_message != CBN_SELCHANGE) {
  240.                 return FALSE;
  241.             }
  242.             idevice = (int)SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETCURSEL, 0, 0L);
  243.             if (idevice == CB_ERR) {
  244.                 return FALSE;
  245.             }
  246.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETLBTEXT, idevice, (LPARAM)(LPSTR)entry);
  247.             if ( (proplist = get_properties(entry)) != (struct prop_item_s *)NULL ) {
  248.                     free((char *)proplist);
  249.                 EnableWindow(GetDlgItem(hDlg, DEVICE_PROP), TRUE);
  250.             }
  251.             else
  252.                 EnableWindow(GetDlgItem(hDlg, DEVICE_PROP), FALSE);
  253.             /* now look up entry in gsview.ini */
  254.             /* and update DEVICE_RES list box */
  255.             GetPrivateProfileString(DEVSECTION, entry, "", buf, sizeof(buf)-2, INIFILE);
  256.             buf[strlen(buf)+1] = '\0';    /* double NULL at end */
  257.                 SendDlgItemMessage(hDlg, DEVICE_RES, CB_RESETCONTENT, 0, 0L);
  258.             p = buf;
  259.             if (*p == '\0') {
  260.                 /* no resolutions can be set */
  261.                 EnableWindow(GetDlgItem(hDlg, DEVICE_RES), FALSE);
  262.                 EnableWindow(GetDlgItem(hDlg, DEVICE_RESTEXT), FALSE);
  263.             }
  264.             else {
  265.               EnableWindow(GetDlgItem(hDlg, DEVICE_RES), TRUE);
  266.               EnableWindow(GetDlgItem(hDlg, DEVICE_RESTEXT), TRUE);
  267.               while (*p!='\0') {
  268.                 res = p;
  269.                 while ((*p!='\0') && (*p!=','))
  270.                 p++;
  271.                 *p++ = '\0';
  272.                     SendDlgItemMessage(hDlg, DEVICE_RES, CB_ADDSTRING, 0, 
  273.                     (LPARAM)((LPSTR)res));
  274.               }
  275.             }
  276.             SendDlgItemMessage(hDlg, DEVICE_RES, CB_SETCURSEL, 0, 0L);
  277.             if (SendDlgItemMessage(hDlg, DEVICE_RES, CB_GETLBTEXT, 0, (LPARAM)(LPSTR)buf)
  278.                 != CB_ERR)
  279.                     SetDlgItemText(hDlg, DEVICE_RES, buf);
  280.             return FALSE;
  281.             case DEVICE_RES:
  282.             /* don't have anything to do */
  283.             return FALSE;
  284.             case DEVICE_PROP:
  285.             idevice = (int)SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETCURSEL, 0, 0L);
  286.             if (idevice == CB_ERR) {
  287.                 return FALSE;
  288.             }
  289.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETLBTEXT, idevice, (LPARAM)(LPSTR)entry);
  290.             if ( (proplist = get_properties(entry)) != (struct prop_item_s *)NULL ) {
  291.                     DLGPROC lpProcProp;
  292.                     free((char *)proplist);
  293.                 LoadString(phInstance, IDS_TOPICPRINT, szHelpTopic, sizeof(szHelpTopic));
  294.                 lpProcProp = (DLGPROC)MakeProcInstance((FARPROC)PropDlgProc, phInstance);
  295.                 DialogBoxParam( phInstance, "PropDlgBox", hDlg, lpProcProp, (LPARAM)entry);
  296.                 FreeProcInstance((FARPROC)lpProcProp);
  297.             }
  298.             else
  299.                 play_sound(SOUND_ERROR);
  300.             return FALSE;
  301.             case IDOK:
  302.             /* save device name and resolution */
  303.                 GetDlgItemText(hDlg, DEVICE_NAME, device_name, sizeof(device_name));
  304.                 GetDlgItemText(hDlg, DEVICE_RES, device_resolution, sizeof(device_resolution));
  305.             EndDialog(hDlg, TRUE);
  306.             return TRUE;
  307.             case IDCANCEL:
  308.             EndDialog(hDlg, FALSE);
  309.             return TRUE;
  310.         }
  311.         break;
  312.     }
  313.     return FALSE;
  314. }
  315.  
  316.  
  317. /* Modeless dialog box - Cancel printing */
  318. BOOL CALLBACK _export
  319. CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  320. {
  321.     switch(message) {
  322.     case WM_INITDIALOG:
  323.         SetWindowText(hDlg, szAppName);
  324.         return TRUE;
  325.     case WM_COMMAND:
  326.         switch(LOWORD(wParam)) {
  327.         case IDCANCEL:
  328.             DestroyWindow(hDlg);
  329.             hDlgModeless = 0;
  330.             EndDialog(hDlg, 0);
  331.             return TRUE;
  332.         }
  333.     }
  334.     return FALSE;
  335. }
  336.  
  337. /* Dialog box to select printer port */
  338. BOOL CALLBACK _export
  339. SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  340. {
  341. LPSTR entry;
  342.     switch(message) {
  343.     case WM_INITDIALOG:
  344.         entry = (LPSTR)lParam;
  345.         while (*entry) {
  346.         SendDlgItemMessage(hDlg, SPOOL_PORT, LB_ADDSTRING, 0, (LPARAM)entry);
  347.         entry += lstrlen(entry)+1;
  348.         }
  349.         SendDlgItemMessage(hDlg, SPOOL_PORT, LB_SETCURSEL, 0, (LPARAM)0);
  350.         return TRUE;
  351.     case WM_COMMAND:
  352.         switch(LOWORD(wParam)) {
  353.         case SPOOL_PORT:
  354. #ifdef WIN32
  355.             if (HIWORD(wParam)
  356. #else
  357.             if (HIWORD(lParam)
  358. #endif
  359.                            == LBN_DBLCLK)
  360.             PostMessage(hDlg, WM_COMMAND, IDOK, 0L);
  361.             return FALSE;
  362.         case IDOK:
  363.             EndDialog(hDlg, 1+(int)SendDlgItemMessage(hDlg, SPOOL_PORT, LB_GETCURSEL, 0, 0L));
  364.             return TRUE;
  365.         case IDCANCEL:
  366.             EndDialog(hDlg, 0);
  367.             return TRUE;
  368.         }
  369.     }
  370.     return FALSE;
  371. }
  372.  
  373. /* Print File to port */
  374. int
  375. gp_printfile(char *filename)
  376. {
  377. #define PRINT_BUF_SIZE 16384u
  378. char *buffer;
  379. char *portname;
  380. DLGPROC lpfnSpoolProc;
  381. int i, port;
  382. HPJOB hJob;
  383. WORD count;
  384. FILE *f;
  385. int error = FALSE;
  386. DLGPROC lpfnCancelProc;
  387. long lsize;
  388. long ldone;
  389. char fmt[MAXSTR];
  390. char pcdone[10];
  391. MSG msg;
  392.  
  393.     /* get list of ports */
  394.     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
  395.         return FALSE;
  396.     GetProfileString("ports", NULL, "", buffer, PRINT_BUF_SIZE);
  397.     /* select a port */
  398.     lpfnSpoolProc = (DLGPROC)MakeProcInstance((FARPROC)SpoolDlgProc, phInstance);
  399.     port = DialogBoxParam(phInstance, "SpoolDlgBox", hwndtext, lpfnSpoolProc, (LPARAM)buffer);
  400.     FreeProcInstance((FARPROC)lpfnSpoolProc);
  401.     if (!port) {
  402.         free(buffer);
  403.         return FALSE;
  404.     }
  405.     portname = buffer;
  406.     for (i=1; i<port && strlen(portname)!=0; i++)
  407.         portname += lstrlen(portname)+1;
  408.     
  409.     if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
  410.         free(buffer);
  411.         return FALSE;
  412.     }
  413.     fseek(f, 0L, SEEK_END);
  414.     lsize = ftell(f);
  415.     if (lsize <= 0)
  416.         lsize = 1;
  417.     fseek(f, 0L, SEEK_SET);
  418.  
  419.     hJob = OpenJob(portname, filename, (HDC)NULL);
  420.     switch ((int)hJob) {
  421.         case SP_APPABORT:
  422.         case SP_ERROR:
  423.         case SP_OUTOFDISK:
  424.         case SP_OUTOFMEMORY:
  425.         case SP_USERABORT:
  426.             fclose(f);
  427.         free(buffer);
  428.             return FALSE;
  429.     }
  430.     if (StartSpoolPage(hJob) < 0)
  431.         error = TRUE;
  432.  
  433.     lpfnCancelProc = (DLGPROC)MakeProcInstance((FARPROC)CancelDlgProc, phInstance);
  434.     hDlgModeless = CreateDialog(phInstance, "CancelDlgBox", hwndimg, lpfnCancelProc);
  435.     ldone = 0;
  436.     LoadString(phInstance, IDS_CANCELDONE, fmt, sizeof(fmt));
  437.  
  438.     while (!error && hDlgModeless 
  439.       && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0 ) {
  440.         if (WriteSpool(hJob, buffer, count) < 0)
  441.         error = TRUE;
  442.         ldone += count;
  443.         sprintf(pcdone, fmt, (int)(ldone * 100 / lsize));
  444.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), pcdone);
  445.         while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
  446.             if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  447.             TranslateMessage(&msg);
  448.             DispatchMessage(&msg);
  449.         }
  450.         }
  451.     }
  452.     free(buffer);
  453.     fclose(f);
  454.  
  455.     if (!hDlgModeless)
  456.         error=TRUE;
  457.     DestroyWindow(hDlgModeless);
  458.     hDlgModeless = 0;
  459.     FreeProcInstance((FARPROC)lpfnCancelProc);
  460.     EndSpoolPage(hJob);
  461.     if (error)
  462.         DeleteJob(hJob, 0);
  463.     else
  464.         CloseJob(hJob);
  465.     return !error;
  466. }
  467.  
  468.  
  469. /* get a filename and spool it for printing */
  470. void
  471. gsview_spool()
  472. {
  473.     static char filename[MAXSTR];
  474.  
  475.     if (!getfilename(filename, OPEN, FILTER_ALL, IDS_PRINTFILE, IDS_TOPICPRINT))
  476.         return;
  477.  
  478.     if (!gp_printfile(filename)) {
  479.         play_sound(SOUND_ERROR);
  480.         return;
  481.     }
  482. }
  483.  
  484.  
  485. char *
  486. get_devices()
  487. {
  488. HGLOBAL hglobal;
  489. LPSTR device;
  490. LPSTR lp;
  491. char *p;
  492.     p = malloc(PROFILE_SIZE);
  493.     if (p == (char *)NULL)
  494.         return (char *)NULL;
  495.  
  496.     GetPrivateProfileString(DEVSECTION, NULL, "", p, PROFILE_SIZE, INIFILE);
  497.     if (strlen(p) == 0) {
  498.         /* [Devices] section doesn't exist.  Initialise from resources */
  499.         hglobal = LoadResource(phInstance, FindResource(phInstance, "gsview_devices", RT_RCDATA));
  500.         if ( (device = (LPSTR)LockResource(hglobal)) == (LPSTR)NULL)
  501.         return (char *)NULL;
  502.         while (lstrlen(device)!=0) {
  503.             for (lp = device; (*lp!='\0') && (*lp!=','); lp++)
  504.                 /* nothing */;
  505.         *lp++ = '\0';
  506.         WritePrivateProfileString(DEVSECTION, device, lp, INIFILE);
  507.         device = lp + lstrlen(lp) + 1;
  508.         }
  509.         FreeResource(hglobal);
  510.     }
  511.     GetPrivateProfileString(DEVSECTION, NULL, "", p, PROFILE_SIZE, INIFILE);
  512.     return p;
  513. }
  514.  
  515. /* cleanup print temporary files */
  516. void
  517. print_cleanup(void)
  518. {
  519.     if ((pcfname[0] != '\0') && !debug)
  520.         unlink(pcfname);
  521.     pcfname[0] = '\0';
  522.     if ((pfname[0] != '\0') && !debug)
  523.         unlink(pfname);
  524.     pfname[0] = '\0';
  525. }
  526.  
  527. /* print a range of pages using a Ghostscript device */
  528. void
  529. gsview_print(BOOL to_file)
  530. {
  531.     int i;
  532.     BOOL flag;
  533.     DLGPROC lpProcDevice;
  534.     float print_xdpi, print_ydpi;
  535.     int width, height;
  536.  
  537.     struct prop_item_s *proplist;
  538.     
  539.     static char output[MAXSTR];    /* output filename for printing */
  540.     char *fname;            /* filename to print */
  541.     char command[256];
  542.     FILE *pcfile;
  543.     FILE *optfile;
  544.     int pages;
  545.     int thispage = pagenum;
  546.  
  547.     if (dfname[0] == '\0') {
  548.         gserror(IDS_NOTOPEN, NULL, MB_ICONEXCLAMATION, SOUND_NOTOPEN);
  549.         return;
  550.     }
  551.     
  552.     LoadString(phInstance, IDS_TOPICPRINT, szHelpTopic, sizeof(szHelpTopic));
  553.     lpProcDevice = (DLGPROC)MakeProcInstance((FARPROC)DeviceDlgProc, phInstance);
  554.     flag = DialogBoxParam( phInstance, "DeviceDlgBox", hwndimg, lpProcDevice, (LPARAM)NULL);
  555.     FreeProcInstance((FARPROC)lpProcDevice);
  556.     if (!flag) {
  557.         return;
  558.     }
  559.  
  560.     info_wait(TRUE);
  561.     gswin_close();    /* we need a new Ghostscript */
  562.     info_wait(FALSE);
  563.  
  564.     fname = (char *)NULL;
  565.     if (doc == (struct document *)NULL) {
  566.         play_sound(SOUND_NONUMBER);
  567.             LoadString(phInstance, IDS_PRINTINGALL, command, sizeof(command));
  568.         if (MessageBox(hwndimg, command, szAppName, MB_OKCANCEL | MB_ICONINFORMATION) == IDCANCEL)
  569.             return;
  570.         fname = dfname;
  571.         pages = 1;
  572.     }
  573.     else {
  574.         pages = 1;
  575.         if (doc->numpages != 0) {
  576.         if (!get_page(&thispage, TRUE))
  577.             return;
  578.             pages = 0;
  579.             for (i=0; i< doc->numpages; i++) {
  580.                 if (page_list.select[i]) pages++;
  581.             }
  582.         }
  583.  
  584.         if ((pcfname[0] != '\0') && !debug)
  585.         unlink(pcfname);
  586.         pcfname[0] = '\0';
  587.         if ( (pcfile = gp_open_scratch_file(szScratch, pcfname, "w")) == (FILE *)NULL) {
  588.         play_sound(SOUND_ERROR);
  589.         return;
  590.         }
  591.         pscopydoc(pcfile);
  592.         fclose(pcfile);
  593.         fname = pcfname;
  594.     }
  595.     
  596.     if (to_file) {
  597.         if (!getfilename(output, SAVE, FILTER_ALL, IDS_OUTPUTFILE, IDS_TOPICPRINT))
  598.         return;
  599.     }
  600.  
  601.     /* calculate image size */
  602.     switch (sscanf(device_resolution,"%fx%f", &print_xdpi, &print_ydpi)) {
  603.         case EOF:
  604.         case 0:
  605.             print_xdpi = print_ydpi = DEFAULT_RESOLUTION;
  606.             break;
  607.         case 1:
  608.             print_ydpi = print_xdpi;
  609.     }
  610.     i = get_papersizes_index();
  611.     if (i < 0) {
  612.         width = user_width;
  613.         width = user_height;
  614.     }
  615.     else {
  616.         width = papersizes[i].width;
  617.         height = papersizes[i].height;
  618.     }
  619.     width  = (unsigned int)(width  / 72.0 * print_xdpi);
  620.     height = (unsigned int)(height / 72.0 * print_ydpi);
  621.  
  622.  
  623.     if ((pfname[0] != '\0') && !debug)
  624.         unlink(pfname);
  625.     pfname[0] = '\0';
  626.     if ( (optfile = gp_open_scratch_file(szScratch, pfname, "w")) == (FILE *)NULL) {
  627.         play_sound(SOUND_ERROR);
  628.         return;
  629.     }
  630.     fprintf(optfile, "-dNOPAUSE\n");
  631.     fprintf(optfile, "-sDEVICE=%s\n",device_name);
  632.     fprintf(optfile, "-r%gx%g\n", (double)print_xdpi, (double)print_ydpi);
  633.     fprintf(optfile, "-g%ux%u\n",width,height);
  634.     if (to_file) {
  635.         char *p;
  636.         fprintf(optfile, "-sOutputFile=");
  637.         for (p=output; *p != '\0'; p++)
  638.             if (*p == '\\')
  639.                 fputc('/',optfile);
  640.             else
  641.                 fputc(*p,optfile);
  642.         fputc('\n',optfile);
  643.     }
  644.     if ((proplist = get_properties(device_name)) != (struct prop_item_s *)NULL) {
  645.         /* output current property selections */
  646.         for (i=0; proplist[i].name[0]; i++) {
  647.         if (strcmp(proplist[i].value, not_defined) != 0)
  648.             fprintf(optfile,"-%s=%s\n", proplist[i].name, proplist[i].value);
  649.         }
  650.         free((char *)proplist);
  651.     }
  652.     fclose(optfile);
  653.  
  654.     sprintf(command,"%s -sGSVIEW=%u @%s %s quit.ps", szGSwin,
  655.         (unsigned int)hwndimg, pfname, fname);
  656.  
  657.     if (strlen(command) > 126) {
  658.         /* command line too long */
  659.         gserror(IDS_TOOLONG, command, MB_ICONSTOP, SOUND_ERROR);
  660.         unlink(pfname);
  661.         pfname[0] = '\0';
  662.         gswin_hinst = (HINSTANCE)NULL;
  663.         return;
  664.     }
  665.     info_wait(TRUE);
  666.     gswin_hinst = (HINSTANCE)WinExec(command, SW_SHOWMINNOACTIVE);
  667.  
  668.     if (gswin_hinst < HINSTANCE_ERROR) {
  669.         gserror(IDS_CANNOTRUN, command, MB_ICONSTOP, SOUND_ERROR);
  670.         unlink(pfname);
  671.         pfname[0] = '\0';
  672.         info_wait(FALSE);
  673.         gswin_hinst = (HINSTANCE)NULL;
  674.         return;
  675.     }
  676.  
  677.     set_timer(timeout*pages);
  678.     info_wait(TRUE);
  679.     return;
  680. }
  681.  
  682. /* extract a range of pages for later printing */
  683. void
  684. gsview_extract()
  685. {
  686.     FILE *f;
  687.     static char output[MAXSTR];
  688.     int thispage = pagenum;
  689.  
  690.     if (dfname[0] == '\0') {
  691.         gserror(IDS_NOTOPEN, NULL, MB_ICONEXCLAMATION, SOUND_NOTOPEN);
  692.         return;
  693.     }
  694.  
  695.     if (doc == (struct document *)NULL) {
  696.         gserror(IDS_NOPAGE, NULL, MB_ICONEXCLAMATION, SOUND_NONUMBER);
  697.         return;
  698.     }
  699.     
  700.     if (doc->numpages != 0)
  701.         if (!get_page(&thispage, TRUE))
  702.             return;
  703.  
  704.     if (!getfilename(output, SAVE, FILTER_PS, NULL, IDS_TOPICPRINT))
  705.         return;
  706.  
  707.     if ((f = fopen(output, "wb")) == (FILE *)NULL) {
  708.         return;
  709.     }
  710.  
  711.     info_wait(TRUE);
  712.     if (doc->numpages != 0)
  713.         pscopydoc(f);
  714.     else
  715.         pscopy(dfile, f, doc->beginheader, doc->endtrailer);
  716.  
  717.     fclose(f);
  718.  
  719.     info_wait(FALSE);
  720.     return;
  721. }
  722.  
  723. /* pscopydoc is copied (with modifications) from ghostview misc.c */
  724. /* Copyright (C) 1992  Timothy O. Theisen */
  725. /* length calculates string length at compile time */
  726. /* can only be used with character constants */
  727. #define length(a) (sizeof(a)-1)
  728.  
  729. /* Copy the headers, marked pages, and trailer to fp */
  730. void
  731. pscopydoc(FILE *fp)
  732. {
  733.     char text[PSLINELENGTH];
  734.     char *comment;
  735.     BOOL pages_written = FALSE;
  736.     BOOL pages_atend = FALSE;
  737.     int pages = 0;
  738.     int page = 1;
  739.     int i;
  740.     long here;
  741.  
  742.     for (i=0; i< doc->numpages; i++) {
  743.         if (page_list.select[i]) pages++;
  744.     }
  745.  
  746.     here = doc->beginheader;
  747.     while ( (comment = pscopyuntil(dfile, fp, here,
  748.                doc->endheader, "%%Pages:")) != (char *)NULL ) {
  749.     here = ftell(dfile);
  750.     if (pages_written || pages_atend) {
  751.         free(comment);
  752.         continue;
  753.     }
  754.     sscanf(comment+length("%%Pages:"), "%s", text);
  755.     if (strcmp(text, "(atend)") == 0) {
  756.         fputs(comment, fp);
  757.         pages_atend = TRUE;
  758.     } else {
  759.         switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  760.         case 1:
  761.             fprintf(fp, "%%%%Pages: %d %d\r\n", pages, i);
  762.             break;
  763.         default:
  764.             fprintf(fp, "%%%%Pages: %d\r\n", pages);
  765.             break;
  766.         }
  767.         pages_written = TRUE;
  768.     }
  769.     free(comment);
  770.     }
  771.     pscopy(dfile, fp, doc->beginpreview, doc->endpreview);
  772.     pscopy(dfile, fp, doc->begindefaults, doc->enddefaults);
  773.     pscopy(dfile, fp, doc->beginprolog, doc->endprolog);
  774.     pscopy(dfile, fp, doc->beginsetup, doc->endsetup);
  775.  
  776.     page = 1;
  777.     for (i = 0; i < doc->numpages; i++) {
  778.     if (page_list.select[map_page(i)])  {
  779.         comment = pscopyuntil(dfile, fp, doc->pages[i].begin,
  780.                   doc->pages[i].end, "%%Page:");
  781.         fprintf(fp, "%%%%Page: %s %d\r\n",
  782.             doc->pages[i].label, page++);
  783.         free(comment);
  784.         pscopy(dfile, fp, -1, doc->pages[i].end);
  785.     }
  786.     }
  787.  
  788.     here = doc->begintrailer;
  789.     while ( (comment = pscopyuntil(dfile, fp, here,
  790.                doc->endtrailer, "%%Pages:")) != (char *)NULL ) {
  791.     here = ftell(dfile);
  792.     if (pages_written) {
  793.         free(comment);
  794.         continue;
  795.     }
  796.     switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  797.         case 1:
  798.         fprintf(fp, "%%%%Pages: %d %d\r\n", pages, i);
  799.         break;
  800.         default:
  801.         fprintf(fp, "%%%%Pages: %d\r\n", pages);
  802.         break;
  803.     }
  804.     pages_written = TRUE;
  805.     free(comment);
  806.     }
  807. }
  808. #undef length
  809.